/*******************************************************************************
 * Copyright (c) 2014 Steffen Mikkelsen
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     Steffen Mikkelsen - initial API and implementation
 ******************************************************************************/
package com.subsecret.secureconnection.securestream.layers;

import static org.junit.Assert.assertNotNull;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import com.subsecret.secureconnection.securestream.SecureStream;
import com.subsecret.secureconnection.securestream.SecureStreamLayer;

public class LayerTestTools {
    private static Random rand = new Random();
    
    public static void testSecureStream(SecureStreamLayer... layers) throws IOException, InterruptedException {
        testSecureStream(true, layers);
    }
    
    public static void testSecureStream(final boolean monitor, final SecureStreamLayer... layers) throws IOException, InterruptedException {
        
        byte[] cTestData = new byte[] { -128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 127 };
        byte[] sTestData = new byte[] { -128, 8, 7, 6, 5, 4, 3, 2, 1, 127 };
        final int port = rand.nextInt(3000) + 60000;
        final ServerSocket ssock = new ServerSocket(port);
        
        final SecureStream[] server = new SecureStream[1];
        final SecureStream[] client = new SecureStream[1];
        final List<Socket> sockets = Collections.synchronizedList(new ArrayList<Socket>());
        Thread t1 = new Thread() {
            @Override
            public void run() {
                try {
                    Socket sock = ssock.accept();
                    server[0] = SecureStream.createSecureStreamServer(sock.getInputStream(), sock.getOutputStream(), monitor);
                    sockets.add(sock);
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        Thread t2 = new Thread() {
            @Override
            public void run() {
                try {
                    Socket sock = new Socket("localhost", port);
                    client[0] = SecureStream.createSecureStreamClient(sock.getInputStream(), sock.getOutputStream(), monitor, layers);
                    sockets.add(sock);
                }
                catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        assertNotNull(server[0]);
        assertNotNull(client[0]);
        
        client[0].getOutputStream().write(cTestData);
        client[0].getOutputStream().flush();
        server[0].getOutputStream().write(sTestData);
        server[0].getOutputStream().flush();
        byte[] cTmp = new byte[sTestData.length];
        byte[] sTmp = new byte[cTestData.length];
        int readS = server[0].getInputStream().read(sTmp);
        int readC = client[0].getInputStream().read(cTmp);
        org.junit.Assert.assertEquals(cTmp.length, readC);
        org.junit.Assert.assertEquals(sTmp.length, readS);
        org.junit.Assert.assertArrayEquals(cTestData, sTmp);
        org.junit.Assert.assertArrayEquals(sTestData, cTmp);
        for (Socket sock : sockets) {
            try {
                sock.close();
            }
            catch (Exception e) {
            }
        }
        ssock.close();
        
    }
}
